package com.atguigu.daijia.dispatch.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.daijia.common.constant.RedisConstant;
import com.atguigu.daijia.dispatch.mapper.OrderJobMapper;
import com.atguigu.daijia.dispatch.service.NewOrderService;
import com.atguigu.daijia.dispatch.xxl.client.XxlJobClient;
import com.atguigu.daijia.map.client.LocationFeignClient;
import com.atguigu.daijia.model.entity.dispatch.OrderJob;
import com.atguigu.daijia.model.enums.OrderStatus;
import com.atguigu.daijia.model.form.map.SearchNearByDriverForm;
import com.atguigu.daijia.model.vo.dispatch.NewOrderTaskVo;
import com.atguigu.daijia.model.vo.map.NearByDriverVo;
import com.atguigu.daijia.model.vo.order.NewOrderDataVo;
import com.atguigu.daijia.order.client.OrderInfoFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import nonapi.io.github.classgraph.json.JSONUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class NewOrderServiceImpl implements NewOrderService {

    @Resource
    private XxlJobClient xxlJobClient;
    @Resource
    private OrderJobMapper orderJobMapper;
    @Resource
    private LocationFeignClient locationFeignClient;
    @Resource
    private OrderInfoFeignClient orderInfoFeignClient;
    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 添加并启动新订单任务
     * 此方法用于根据订单ID查询是否存在对应的OrderJob，如果不存在，则通过xxlJobClient添加并启动一个新的任务
     * 同时会在OrderJob表中插入一条记录，关联订单ID和任务ID
     *
     * @param newOrderTaskVo 新订单任务的参数对象，包含订单ID等信息
     * @return 返回新添加的任务的ID，如果任务已存在则返回0
     */
    @Override
    public Long addAndStartTask(NewOrderTaskVo newOrderTaskVo) {
        // 根据订单ID查询对应的OrderJob
        OrderJob orderJob = orderJobMapper.selectOne(new LambdaQueryWrapper<OrderJob>().
                eq(OrderJob::getOrderId, newOrderTaskVo.getOrderId()));
        if(orderJob == null){
            // 如果OrderJob不存在，通过xxlJobClient添加并启动新任务
            Long newOrderTaskId = xxlJobClient.addAndStart("newOrderTaskHandler", "",
                    "0 0/1 * * * ?", "创建id为" + newOrderTaskVo.getOrderId() + "的用户打车订单任务");

            // 创建一个新的OrderJob对象并设置相关属性
            orderJob = new OrderJob();
            orderJob.setOrderId(newOrderTaskVo.getOrderId());
            orderJob.setJobId(newOrderTaskId);
            orderJob.setParameter(JSONObject.toJSONString(newOrderTaskVo));
            // 将新的OrderJob插入数据库
            orderJobMapper.insert(orderJob);
        }
        // 返回任务ID，如果任务已存在则返回0
        return orderJob.getJobId();
    }

    /**
     * 执行指定的订单任务
     *
     * @param jobId 订单任务ID
     * @return 执行成功返回true，否则返回false
     */
    @Override
    public Boolean executeTask(Long jobId) {
        // 根据任务ID查询订单任务信息
        OrderJob orderJob = orderJobMapper.selectOne(new LambdaQueryWrapper<OrderJob>().eq(OrderJob::getJobId, jobId));
        // 如果订单任务不存在，则直接返回成功
        if(orderJob == null){
            System.err.println("订单任务不存才");
            return true;
        }
        // 将订单任务参数解析为新订单任务对象
        NewOrderTaskVo newOrderTaskVo = JSONObject.parseObject(orderJob.getParameter(), NewOrderTaskVo.class);
        // 查询订单状态
        Integer orderStatus = orderInfoFeignClient.getOrderStatus(newOrderTaskVo.getOrderId()).getData();
        // 如果订单状态不是等待接单状态，则启动任务并返回成功
        if(orderStatus.intValue() != OrderStatus.WAITING_ACCEPT.getStatus().intValue()){
            xxlJobClient.startJob(jobId);
            log.info("停止任务调度：{}",JSONObject.toJSONString(newOrderTaskVo));
            return true;
        }
        // 构建搜索附近司机的请求对象
        SearchNearByDriverForm searchNearByDriverForm = new SearchNearByDriverForm();
        System.err.println("newOrderTaskVo："+JSONObject.toJSONString(newOrderTaskVo));
        searchNearByDriverForm.setLatitude(newOrderTaskVo.getStartPointLatitude());
        searchNearByDriverForm.setLongitude(newOrderTaskVo.getStartPointLongitude());
        searchNearByDriverForm.setMileageDistance(newOrderTaskVo.getExpectDistance());
        // 调用接口搜索附近司机
        List<NearByDriverVo> nearByDriverVos = locationFeignClient.searchNearByDriver(searchNearByDriverForm).getData();
        System.err.println("nearByDriverVos："+JSONObject.toJSONString(nearByDriverVos));
        // 遍历附近司机，将订单信息推送给每个司机
        nearByDriverVos.forEach(driver -> {
            // 构建Redis中司机接单去重列表的键
            String repeatKey = RedisConstant.DRIVER_ORDER_REPEAT_LIST + newOrderTaskVo.getOrderId();
            // 检查当前司机是否已经接收过此订单信息
            Boolean isMember = redisTemplate.opsForSet().isMember(repeatKey, driver.getDriverId());
            // 如果司机尚未接收此订单信息
            if(!isMember){
                // 将司机ID添加到去重列表中，并设置过期时间
                redisTemplate.opsForSet().add(repeatKey, driver.getDriverId());
                redisTemplate.expire(repeatKey, RedisConstant.DRIVER_ORDER_REPEAT_LIST_EXPIRES_TIME, TimeUnit.MINUTES);
                // 构建新订单数据对象
                NewOrderDataVo newOrderDataVo = new NewOrderDataVo();
                newOrderDataVo.setOrderId(newOrderTaskVo.getOrderId());
                newOrderDataVo.setStartLocation(newOrderTaskVo.getStartLocation());
                newOrderDataVo.setEndLocation(newOrderTaskVo.getEndLocation());
                newOrderDataVo.setExpectAmount(newOrderTaskVo.getExpectAmount());
                newOrderDataVo.setExpectDistance(newOrderTaskVo.getExpectDistance());
                newOrderDataVo.setExpectTime(newOrderTaskVo.getExpectTime());
                newOrderDataVo.setFavourFee(newOrderTaskVo.getFavourFee());
                newOrderDataVo.setDistance(driver.getDistance());
                newOrderDataVo.setCreateTime(newOrderTaskVo.getCreateTime());
                // 将订单信息转换为JSON字符串并存入司机的临时订单列表中，并设置过期时间
                String key = RedisConstant.DRIVER_ORDER_TEMP_LIST + driver.getDriverId();
                redisTemplate.opsForList().leftPush(key, JSONObject.toJSONString(newOrderDataVo));
                redisTemplate.expire(key, RedisConstant.DRIVER_ORDER_TEMP_LIST_EXPIRES_TIME, TimeUnit.MINUTES);
                // 记录日志
                log.info("该新订单信息已经放入司机临时队列：{}", JSONObject.toJSONString(newOrderDataVo));
            }
        });
        // 返回成功
        return true;
    }

    /**
     * 查询司机的最新订单队列数据
     *
     * @param driverId 司机ID，用于定位特定司机的订单数据
     * @return 返回司机的最新订单数据列表，如果没有数据，则返回空列表
     */
    @Override
    public List<NewOrderDataVo> findNewOrderQueueData(Long driverId) {
        // 初始化订单数据列表
        List<NewOrderDataVo> list = new ArrayList<>();
        // 构建Redis中的司机临时订单列表的键
        String key = RedisConstant.DRIVER_ORDER_TEMP_LIST + driverId;
        // 获取司机临时订单列表的长度
        Long size = redisTemplate.opsForList().size(key);
        System.err.println("size："+size);
        // 如果列表中有数据
        if(size > 0){
            // 遍历列表，获取所有数据
            for(int i=0; i<size; i++){
                // 从列表左侧弹出数据，转换为String类型
                String data = (String) redisTemplate.opsForList().leftPop(key);
                // 将弹出的数据解析为NewOrderDataVo对象，并添加到列表中
                list.add(JSONObject.parseObject(data, NewOrderDataVo.class));
            }
        }
        // 返回司机的最新订单数据列表
        return list;
    }

    /**
     * 清空指定司机的新订单队列数据
     *
     * @param driverId 司机的ID，用于定位特定司机的订单数据
     * @return 返回操作是否成功，总是返回true，表示成功清空数据
     */
    @Override
    public Boolean clearNewOrderQueueData(Long driverId) {
        String key = RedisConstant.DRIVER_ORDER_TEMP_LIST + driverId;
        redisTemplate.delete(key);
        return true;
    }
}
